#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>

#include "ErreurInterpreteur.h"
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin FIN_FICHIER
	
	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqInst> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while (this->isVariable() || this->isInstSi() || this->isInstSelon() ||
			this->isInstTq() || this->isInstRepeter() || this->isInstPour() ||
			this->isInstLire() || this->isInstEcrire());
	// tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::inst() {
// <inst> ::= <affectation> | <instSi> | <instSelon> | <instTq> |
//		<instRepeter> | <instPour> | <instLire> | <instEcrire>

	if(this->isVariable()){
		affectation();
	}
	else if(this->isInstSi()){
		instSi();
	}
	else if(this->isInstSelon()){
		instSelon();
	}
	else if(this->isInstTq()){
		instTq();
	}
	else if(this->isInstRepeter()){
		instRepeter();
	}
	else if(this->isInstPour()){
		instPour();
	}
	else if(this->isInstLire()){
		instLire();
	}
	else if(this->isInstEcrire()){
		instEcrire();
	}
	else{
		erreur("<inst>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = <expression>

	testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	expression();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }

	terme();
	while (this->isOpAdd()){
		opAdd();
		terme();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::terme(){
// <terme> ::= <facteur> {<opMult> <facteur>}
	
	facteur();
	while (this->isOpMult()){
		opMult();
		facteur();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::facteur() {
// <facteur> ::= <entier> | <variable> | <chaine> | <opUnaire> <expBool> | ( <expBool> )

	if (this->isVariable()
			|| this->isEntier()
			|| this->isChaine())
	{
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	}
	else if (this->isOpUnaire()) {
		opUnaire();
		expBool();
	}
	else if (ls.getSymCour()=="(") {
		ls.suivant();
		expBool();
		sauterSymCour(")");
	}
	else
		erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expBool() {
// <expBool> ::= <termBool> { <opOu> <termBool> }
	
	termBool();
	while(this->isOpOu()){
		opOu();
		termBool();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::termBool() {
// <termBool> ::= <relation> { <opEt> <relation> }
	
	relation();
	while(this->isOpEt()){
		opEt();
		relation();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::relation(){
// <relation> ::= <expression> { <opRel> <expression> }
	expression();
	while(this->isOpRel()){
		opRel();
		expression();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opEt(){
// <opEt> ::= et
	
	if (this->isOpEt()){
		ls.suivant();
	}
	else{
		erreur("<opEt>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opOu(){
// <opOu> ::= ou
	
	if (this->isOpOu()){
		ls.suivant();
	}
	else{
		erreur("<opOu>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opRel(){
// <opRel> ::= == | != | < | <= | > | >=
	
	if (this->isOpRel()){
		ls.suivant();
	}
	else{
		erreur("<opRel>");
	}
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opAdd()
// <opAdd> ::= + | -
{
	if (this->isOpAdd()){
		ls.suivant();
	}
	else{
		erreur("<opAdd>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opMult(){
// <opMult> ::= * | /
	
	if(this->isOpMult()){
		ls.suivant();
	}
	else{
		erreur("<opMult>");
	}
}

void LecteurPhraseAvecTable::opUnaire(){
// <opUnaire> ::= - | non
	
	if(this->isOpUnaire()){
		ls.suivant();
	}
	else{
		erreur("<opMult>");
	}
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSi(){
// <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi
	
	if(this->isInstSi()){
		ls.suivant();
		sauterSymCour("(");
		expBool();
		sauterSymCour(")");
		seqInst();
		
		while(ls.getSymCour()=="sinonsi"){
			ls.suivant();
			sauterSymCour("(");
			expBool();
			sauterSymCour(")");
			seqInst();
		}
		
		if(ls.getSymCour()=="sinon"){
			ls.suivant();
			seqInst();
		}
		sauterSymCour("finsi");
	}
	else{
		erreur("<instSi>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSelon(){
//	 <instSelon> ::= selon ( <variable> ) cas <expression> : <seqInst>
//			{ cas <expression> : <seqInst> } [ defaut : <seqInst> ] finselon
	if(this->isInstSelon()){
		sauterSymCour("selon");
		sauterSymCour("(");
		testerSymCour("<VARIABLE>");
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		sauterSymCour(")");
		do{
			sauterSymCour("cas");
			expression();
			sauterSymCour(":");
			seqInst();
		} while (ls.getSymCour()=="cas");
		if(ls.getSymCour()=="defaut"){
			ls.suivant(),
			sauterSymCour(":");
			seqInst();
		}
		sauterSymCour("finselon");
	}
	else{
		erreur("<instSelon>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instTq(){
// <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
	
	if(this->isInstTq()){
		ls.suivant();
		sauterSymCour("(");
		expBool();
		sauterSymCour(")");
		seqInst();
		sauterSymCour("fintantque");
	}
	else{
		erreur("<instTq>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instRepeter(){
// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
	
	if(this->isInstRepeter()){
		ls.suivant();
		seqInst();
		sauterSymCour("jusqua");
		sauterSymCour("(");
		expBool();
		sauterSymCour(")");
	}
	else{
		erreur("<instRepeter>");
	}

}

void LecteurPhraseAvecTable::instPour(){
// <instPour> ::= pour ( <affectation> ; <expBool> ; <inst> ) <seqInst> finpour
	if (this->isInstPour()){
		sauterSymCour("pour");
		sauterSymCour("(");
		affectation();
		sauterSymCour(";");
		expBool();
		sauterSymCour(";");
		inst();
		sauterSymCour(")");
		seqInst();
		sauterSymCour("finpour");
	}
	else
	{
		erreur("<instPour>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instLire(){
// <instLire> ::= lire ( <variable> )

	if(this->isInstLire()){
		sauterSymCour("lire");
		sauterSymCour("(");
		testerSymCour("<VARIABLE>");
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		sauterSymCour(")");
	}
	else{
		erreur("<instLire>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instEcrire(){
// <instEcrire> ::= ecrire ( <expression> )
	if(this->isInstEcrire()){
		sauterSymCour("ecrire");
		sauterSymCour("(");
		expression();
		sauterSymCour(")");
	}
	else{
		erreur("<instEcrire>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		throw ErreurTestSymbole(); // levée d'exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	throw ErreurStandard(); // levée d'exception
}
